#
# deploy.rb
#
# author: Andrew Smith <andrewrs@cs.washington.edu>
# modified: 6 May 2011
#
# Deployment script and settings for Capistrano. This defines all the settings
# needed to run cap deploy and launch the latest version of the web app.
#

set :application, "lab-system"
set :repository,  "https://lab-specimen-transport-system.googlecode.com/hg/"

set :scm, :mercurial

server "ec2-50-19-110-56.compute-1.amazonaws.com", :app, :web, :db, :primary => true

set :deploy_to, "/var/www/#{application}"
set :user, "bitnami"
set :group, "nogroup"

namespace :deploy do
  # Using Passenger with nginx
  
  task :start do ; end
  
  task :stop do ; end
  
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "#{try_sudo} touch #{File.join(current_path,'rails','tmp','restart.txt')}"
  end

  desc <<-DESC
    Prepares one or more servers for deployment. Before you can use any \
    of the Capistrano deployment tasks with your project, you will need to \
    make sure all of your servers have been prepared with `cap deploy:setup'. When \
    you add a new server to your cluster, you can easily run the setup task \
    on just that server by specifying the HOSTS environment variable:

      $ cap HOSTS=new.server.com deploy:setup

    It is safe to run this task on servers that have already been set up; it \
    will not destroy any deployed revisions or data.
  DESC
  task :setup, :except => { :no_release => true } do
    dirs = [deploy_to, releases_path, shared_path]
    dirs += shared_children.map { |d| File.join(shared_path, d) }
    run <<-CMD
      #{try_sudo} mkdir -p #{dirs.join(' ')} &&
      #{try_sudo} chown #{user}:#{group} #{dirs.join(' ')} &&
      #{try_sudo} chmod g+w #{dirs.join(' ')}
    CMD
  end
  
  desc <<-DESC
    [internal] Touches up the released code. This is called by update_code \
    after the basic deploy finishes. It assumes a Rails project was deployed, \
    so if you are deploying something else, you may want to override this \
    task with your own environment's requirements.

    This task will make the release group-writable (if the :group_writable \
    variable is set to true, which is the default). It will then set up \
    symlinks to the shared directory for the log, system, and tmp/pids \
    directories, and will lastly touch all assets in public/images, \
    public/stylesheets, and public/javascripts so that the times are \
    consistent (so that asset timestamping works).  This touch process \
    is only carried out if the :normalize_asset_timestamps variable is \
    set to true, which is the default The asset directories can be overridden \
    using the :public_children variable.
  DESC
  task :finalize_update, :except => { :no_release => true } do
    run "chmod -R g+w #{latest_release}/rails" if fetch(:group_writable, true)

    # mkdir -p is making sure that the directories are there for some SCM's that don't
    # save empty folders
    run <<-CMD
      rm -rf #{latest_release}/rails/log #{latest_release}/rails/public/system #{latest_release}/rails/tmp/pids &&
      mkdir -p #{latest_release}/rails/public &&
      mkdir -p #{latest_release}/rails/tmp &&
      ln -s #{shared_path}/log #{latest_release}/rails/log &&
      ln -s #{shared_path}/system #{latest_release}/rails/public/system &&
      ln -s #{shared_path}/pids #{latest_release}/rails/tmp/pids
    CMD

    if fetch(:normalize_asset_timestamps, true)
      stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
      asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{latest_release}/rails/public/#{p}" }.join(" ")
      run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" }
    end
  end
  
  desc <<-DESC
    Run the migrate rake task. By default, it runs this in most recently \
    deployed version of the app. However, you can specify a different release \
    via the migrate_target variable, which must be one of :latest (for the \
    default behavior), or :current (for the release indicated by the \
    `current' symlink). Strings will work for those values instead of symbols, \
    too. You can also specify additional environment variables to pass to rake \
    via the migrate_env variable. Finally, you can specify the full path to the \
    rake executable by setting the rake variable. The defaults are:

      set :rake,           "rake"
      set :rails_env,      "production"
      set :migrate_env,    ""
      set :migrate_target, :latest
  DESC
  task :migrate, :roles => :db, :only => { :primary => true } do
    rake = fetch(:rake, "rake")
    rails_env = fetch(:rails_env, "production")
    migrate_env = fetch(:migrate_env, "")
    migrate_target = fetch(:migrate_target, :latest)

    directory = case migrate_target.to_sym
      when :current then File.join(current_path, 'rails')
      when :latest  then File.join(latest_release, 'rails')
      else raise ArgumentError, "unknown migration target #{migrate_target.inspect}"
      end

    run "cd #{directory}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate"
  end
  
  after 'deploy', 'deploy:cleanup'
  after 'deploy:migrations', 'deploy:cleanup'
end

namespace :nginx do  
  [:stop, :start, :restart].each do |t|
    desc "#{t}s the nginx server"
    task t do
      run "#{try_sudo} /opt/bitnami/nginx/scripts/ctl.sh #{t}"
    end
  end
  
  desc "Copies the appropriate config file for the ngnix server"
  task :configure do
    run "#{try_sudo} cp #{latest_release}/rails/config/nginx.conf /opt/bitnami/nginx/conf/vhosts/#{application}.conf"
  end
  
  after 'deploy:setup', 'nginx:configure'
end

namespace :db do
  desc "Creates the shared database.yml file for the deployment"
  task :setup do
    run <<-CMD
      mkdir -p #{shared_path}/config &&
      cp -n #{latest_release}/rails/config/database.yml.sample #{shared_path}/config/database.yml
    CMD
    puts "Don't forget to edit shared/config/database.yml to update the database"
    puts "connection details. This will be used for deployment."
  end
  
  desc "Copies the appropriate database.yml file to the running application"
  task :symlink, :except => { :no_release => true } do
    run "ln -nfs #{shared_path}/config/database.yml #{current_release}/rails/config/database.yml"
  end
  
  after 'deploy:setup',           'db:setup'    unless fetch(:skip_db_setup, false)
  after 'deploy:finalize_update', 'db:symlink'
end